#include "ExportFileService.h"

ExportFileService::ExportFileService()
{

}

bool ExportFileService::init(QString ID,QString mingCheng,QString path)
{
    filename = path + mingCheng+".xlsx"; // 不加实验id的导出文件名称
    // 设置数字字体格式
    numericFormat.setHorizontalAlignment(QXlsx::Format::AlignLeft);

    //新建xlsx文件
    QXlsx::Document xlsx;
    //新建sheet页
    xlsx.addSheet("样本设置");
    xlsx.addSheet("拟合数据");
    xlsx.addSheet("扩增数据");
    xlsx.addSheet("原始数据");

    //保存文件
    if (!xlsx.saveAs(filename))
    {
        return false;
    }
    return true;

}


bool ExportFileService::yangben2EXCEL(QList<QString> info,Sample sampleList[96],Target targetList[96][20])
{

    //打开现存xlsx文件
    QXlsx::Document xlsx(filename);
    //选择样本设置表
    xlsx.selectSheet("样本设置");
    // 获取当前sheet页
    QXlsx::Worksheet *curSheet = xlsx.currentWorksheet();

    vector<QString> attribute1 ={"设备名称","设备型号","设备序列号","信号平滑","创建日期",
                                 "参比荧光","实验名称","实验文件名","实验编码","实验注释",
                                 "实验类型","实验运行结束时间","用户名","读后阶段/步骤数",
                                 "量化循环数方法","预读阶段/步骤数"
                                };


    int len1 = attribute1.size();

    //1、插入基本信息的表头

    LOG << "插入基本信息的表头开始";

    for (int i=0 ; i<len1; i++)
    {
        curSheet->writeString(i+1,1,attribute1[i]);
    }

    vector<QString> attribute2 ={"反应孔","反应孔位置","样本名","样本颜色","基因名称",
                                 "基因颜色","样本类型","报告基团","淬灭基团","数量","注释"
                                };
    int len2 = attribute2.size();

    LOG << "插入基本信息的表头结束";

    LOG << "2、插入反应板的表头开始";

    //2、插入反应板的表头
    for(int i=0; i<len2; i++)
    {
        curSheet->writeString(len1+2,i+1,attribute2[i]);
    }

    LOG << "2、插入反应板的表头结束";
    LOG << "3、插入基本信息开始";

    //3、插入基本信息
    if(info.size() != 0)
    {

        for (int i=0; i<len1 ; i++)
        {
            curSheet->writeString(i+1,2,info[i]);
        }

    }

    LOG << "3、插入基本信息结束";

    LOG << "4、插入反应板数据开始";

    //4、插入反应板数据

    //获取反应板信息
    reactionInfo = disposeReactionWells(sampleList,targetList);

    int len3 = reactionInfo.size();

    for (int i=0; i<len3; i++)
    {
        int row = len1+3+i;
        curSheet->writeNumeric(row,1,reactionInfo[i].value("num").toFloat(), numericFormat);
        curSheet->writeString(row,2,reactionInfo[i].value("place"));
        curSheet->writeString(row,3,reactionInfo[i].value("sampleName"));
        curSheet->writeString(row,4,reactionInfo[i].value("sampleColor"));
        curSheet->writeString(row,5,reactionInfo[i].value("targetName"));
        curSheet->writeString(row,6,reactionInfo[i].value("targetColor"));
        curSheet->writeString(row,7,reactionInfo[i].value("task"));
        curSheet->writeString(row,8,reactionInfo[i].value("reporter"));
        curSheet->writeString(row,9,reactionInfo[i].value("quencher"));
        curSheet->writeString(row,10,reactionInfo[i].value("quantity"));
        curSheet->writeString(row,11,reactionInfo[i].value("explain"));
        // 休眠
        this->sleep(EXPORT_SLEEP_TIME);
    }

    LOG << "4、插入反应板数据结束";


    //保存文件
    if (!xlsx.saveAs(filename))
    {
        return false;
    }
    return true;
}

bool ExportFileService::yuanshi2EXCEL(QList<QString> info,QList<QList<QHash<QString, QString>>> yingGuangData)
{
    //打开现存xlsx文件
    QXlsx::Document xlsx(filename);
    //选择样本设置表
    xlsx.selectSheet("原始数据");
    // 获取当前sheet页
    QXlsx::Worksheet *curSheet = xlsx.currentWorksheet();

    //1、插入基本信息的表头
    vector<QString> attribute1 ={"设备名称","设备型号","设备序列号","信号平滑化","创建日期",
                                 "参比荧光","实验名称","实验文件名","实验编码","实验注释",
                                 "实验类型","实验运行结束时间","用户名","读后阶段/步骤数",
                                 "量化循环数方法","预读阶段/步骤数"
                                };

    int len1 = attribute1.size();
    for (int i=0 ; i<len1; i++)
    {
        curSheet->writeString(i+1,1,attribute1[i]);
    }


    //2、插入反应板的表头
    vector<QString> attribute2 ={"反应孔","反应孔位置", "循环数",
                                 "FAM","VIC","ROX","CY5",
                                 "x5","x6","x7","x8"
                                };
    int len2 = attribute2.size();
    for(int i=0; i<len2; i++)
    {
        curSheet->writeString(len1+2,i+1,attribute2[i]);
    }

    //3、插入基本信息数据

    if(info.size() != 0)
    {
        for (int i=0 ; i<len1 ; i++)
        {
            curSheet->writeString(i+1,2,info[i]);
        }
    }

    //4、插入反应孔的应该值

    if(yingGuangData.size() != 0)
    {

        int rows = len1+3;     //反应板插入数据的行数
        int cycles_number = 1; //定义循环数

        QList <QString>reactionPlace;  //定义反应孔

        if(yingGuangData[0].size() == 32)
        {
            reactionPlace = reactionPlace32;
        }
        else if(yingGuangData[0].size() == 16)
        {
            reactionPlace = reactionPlace16;
        }

        LOG << "原始荧光导出开始";

        for(int index=0; index<yingGuangData.size(); index++)
        {
            int reaction_number = 0;   //定义反应孔数 1~96

            //将第二层qlist中的数据按照A1~A12的顺序插入
            for (int i=0; i<8; i++)
            {
                for (int j=i; j<yingGuangData[0].size(); j+=8)
                {
                    curSheet->writeNumeric(rows,1,static_cast<double>(reaction_number+1), numericFormat);
                    curSheet->writeString(rows,2,reactionPlace[reaction_number]);
                    curSheet->writeNumeric(rows,3,static_cast<double>(cycles_number), numericFormat);
                    curSheet->writeNumeric(rows,4,yingGuangData[index][j].value("1").toFloat(), numericFormat);
                    curSheet->writeNumeric(rows,5,yingGuangData[index][j].value("2").toFloat(), numericFormat);
                    curSheet->writeNumeric(rows,6,yingGuangData[index][j].value("3").toFloat(), numericFormat);
                    curSheet->writeNumeric(rows,7,yingGuangData[index][j].value("4").toFloat(), numericFormat);
                    curSheet->writeNumeric(rows,8,0, numericFormat);
                    curSheet->writeNumeric(rows,9,0, numericFormat);
                    curSheet->writeNumeric(rows,10,0, numericFormat);
                    curSheet->writeNumeric(rows,11,0, numericFormat);

                    //每插入完一行后将rows加1
                    rows++;
                    //每插入完一行将reaction_number加1
                    reaction_number++;
                }

            }
            //每完成一轮外层循环，循环数加1
            cycles_number++;

            // 休眠
            this->sleep(EXPORT_SLEEP_TIME);
        }

    }

    LOG << "原始荧光导出结束";

    //保存文件
    if (!xlsx.saveAs(filename))
    {
        return false;
    }
    return true;

}

bool ExportFileService::yingguang2EXCEL(QList<QString> info,QList<QList<QHash<QString, QString>>> yingGuangData)
{

    //打开现存xlsx文件
    QXlsx::Document xlsx(filename);
    //选择样本设置表
    xlsx.selectSheet("拟合数据");
    // 获取当前sheet页
    QXlsx::Worksheet *curSheet = xlsx.currentWorksheet();

    //1、插入基本信息的表头
    vector<QString> attribute1 ={"设备名称","设备型号","设备序列号","信号平滑化","创建日期",
                                 "参比荧光","实验名称","实验文件名","实验编码","实验注释",
                                 "实验类型","实验运行结束时间","用户名","读后阶段/步骤数",
                                 "量化循环数方法","预读阶段/步骤数"
                                };

    int len1 = attribute1.size();
    for (int i=0 ; i<len1; i++)
    {
        curSheet->writeString(i+1,1,attribute1[i]);
    }


    //2、插入反应板的表头
    vector<QString> attribute2 ={"反应孔","反应孔位置", "循环数",
                                 "FAM","VIC","ROX","CY5",
                                 "x5","x6","x7","x8"
                                };
    int len2 = attribute2.size();
    for(int i=0; i<len2; i++)
    {
        curSheet->writeString(len1+2,i+1,attribute2[i]);
    }

    //3、插入基本信息数据

    if(info.size() != 0)
    {
        for (int i=0 ; i<len1 ; i++)
        {
            curSheet->writeString(i+1,2,info[i]);
        }
    }

    //4、插入反应孔的应该值

    if(yingGuangData.size() != 0)
    {

        int rows = len1+3;     //反应板插入数据的行数
        int cycles_number = 1; //定义循环数

        QList <QString>reactionPlace;  //定义反应孔

        if(yingGuangData[0].size() == 32)
        {
            reactionPlace = reactionPlace32;
        }
        else if(yingGuangData[0].size() == 16)
        {
            reactionPlace = reactionPlace16;
        }

        LOG << "拟合荧光导出开始";

        for(int index=0; index<yingGuangData.size(); index++)
        {
            int reaction_number = 0;   //定义反应孔数 1~96

            //将第二层qlist中的数据按照A1~A12的顺序插入
            for (int i=0; i<8; i++)
            {
                for (int j=i; j<yingGuangData[0].size(); j+=8)
                {
                    curSheet->writeNumeric(rows,1,static_cast<double>(reaction_number+1), numericFormat);
                    curSheet->writeString(rows,2,reactionPlace[reaction_number]);
                    curSheet->writeNumeric(rows,3,static_cast<double>(cycles_number), numericFormat);
                    curSheet->writeNumeric(rows,4,(QString::number(yingGuangData[index][j].value("1").toDouble(), 'f', 0)).toInt(), numericFormat);
                    curSheet->writeNumeric(rows,5,(QString::number(yingGuangData[index][j].value("2").toDouble(), 'f', 0)).toInt(), numericFormat);
                    curSheet->writeNumeric(rows,6,(QString::number(yingGuangData[index][j].value("3").toDouble(), 'f', 0)).toInt(), numericFormat);
                    curSheet->writeNumeric(rows,7,(QString::number(yingGuangData[index][j].value("4").toDouble(), 'f', 0)).toInt(), numericFormat);
                    curSheet->writeNumeric(rows,8,0, numericFormat);
                    curSheet->writeNumeric(rows,9,0, numericFormat);
                    curSheet->writeNumeric(rows,10,0, numericFormat);
                    curSheet->writeNumeric(rows,11,0, numericFormat);

                    //每插入完一行后将rows加1
                    rows++;
                    //每插入完一行将reaction_number加1
                    reaction_number++;

                }

            }
            //每完成一轮外层循环，循环数加1
            cycles_number++;

            // 休眠
            this->sleep(EXPORT_SLEEP_TIME);
        }

    }

    LOG << "拟合荧光导出结束";

    //保存文件
    if (!xlsx.saveAs(filename))
    {
        return false;
    }
    return true;

}

bool ExportFileService::kuozeng2EXCEL(QList<QString> info,QList<QList<QHash<QString, QString>>> niheyingGuangData,QList<QList<QHash<QString, QString>>> deltayingGuangData,QHash<QString,QString> targetTable,
                                      QList<QString> ct, QString haoCai)
{

    //打开现存xlsx文件
    QXlsx::Document xlsx(filename);
    //选择样本设置表
    xlsx.selectSheet("扩增数据");
    // 获取当前sheet页
    QXlsx::Worksheet *curSheet = xlsx.currentWorksheet();
    // 设置ct值写入样式
    QXlsx::Format ctFormat;
    ctFormat.setHorizontalAlignment(QXlsx::Format::AlignLeft);
    ctFormat.setNumberFormat("0.00"); // 数字显示格式：保留两位小数

    LOG << "ct导出之前";

    //1、插入基本信息的表头
    vector<QString> attribute1 ={"设备名称","设备型号","设备序列号","信号平滑","创建日期",
                                 "参比荧光","实验名称","实验文件名","实验编码","实验注释",
                                 "实验类型","实验运行结束时间","用户名","读后阶段/步骤数",
                                 "量化循环数方法","预读阶段/步骤数"
                                };
    int len1 = attribute1.size();
    for (int i=0 ; i<len1; i++)
    {
        curSheet->writeString(i+1,1,attribute1[i]);
    }

    //2、插入反应板的表头
    vector<QString> attribute2 ={"反应孔","反应孔位置",
                                 "循环数","基因名称",
                                 "Rn","ΔRn","Ct"
                                };
    int len2 = attribute2.size();
    for(int i=0; i<len2; i++)
    {
        curSheet->writeString(len1+2,i+1,attribute2[i]);
    }



    //3、插入基本信息数据
    if(info.size() != 0)
    {
        for (int i=0 ; i<len1 ; i++)
        {
            curSheet->writeString(i+1,2,info[i]);
        }
    }


    //4、插入反应板数据

    if(niheyingGuangData.size() != 0)
    {
        QList <QString>reactionPlace;  //定义反应孔
        int haoCai2Col; // 根据反应板耗材选择不同的反应板列数

        //        reactionPlace = reactionPlace32;
        if(haoCai.contains("管式"))
        {
            haoCai2Col = 4;
            reactionPlace = reactionPlace32;
        }
        else if(haoCai.contains("芯片"))
        {
            haoCai2Col = 2;
            reactionPlace = reactionPlace16;
        }

        //处理ct数据
        vector<vector<QString>> ctInfo;
        QHash<QString,int> Target_number = {{"Target1",0},{"Target2",1},{"Target3",2},{"Target4",3}};

        // ct的循环数和孔位对调
        if(ct.size() != 0)
        {
            // 32孔
            if(haoCai2Col == 4){
                int ctStep = ct.size()/4;
                for (int i=0; i<ctStep; i++)
                {
                    vector<QString> tmp;
                    for (int j=0; j<4; j++)
                    {
                        tmp.push_back(ct[(i*4)+j]);
                    }
                    ctInfo.push_back(tmp);
                }
            }

            // 16孔
            if(haoCai2Col == 2){
                for(int i = 0; i < ct.size(); i += 16){
                    vector<QString> tmp;
                    for(int j = 0; j < 4; j++){
                        tmp.push_back(ct[i+j]);
                    }
                    ctInfo.push_back(tmp);
                    int step2 = i + 4;
                    vector<QString> tmp2;
                    for(int j = 0; j < 4; j++){
                        tmp2.push_back(ct[step2 + j]);
                    }
                    ctInfo.push_back(tmp2);
                }
            }
        }

        QList<QList<QHash<QString, QString>>> tKuozengData; //临时荧光数据
        QList<QList<QHash<QString, QString>>> tDeltaKuozengData; //临时delta荧光数据

        // 数据行列互换
        for(int i = 0; i < niheyingGuangData.size(); i++){
            QList<QHash<QString, QString>> tKuozengSingularData; //临时荧光数据
            QList<QHash<QString, QString>> tDeltaKuozengSingularData; //临时delta荧光数据
            for(int j = 0; j < 8; j++){
                for(int k = 0; k < haoCai2Col; k++){
                    tKuozengSingularData.append(niheyingGuangData[i][j + k*8]);
                    tDeltaKuozengSingularData.append(deltayingGuangData[i][j + k*8]);
                }
            }
            tKuozengData.append(tKuozengSingularData);
            tDeltaKuozengData.append(tDeltaKuozengSingularData);
        }
        niheyingGuangData = tKuozengData;
        deltayingGuangData = tDeltaKuozengData;

        // 数据内层和外层互换
        QList<QList<QHash<QString, QString>>> kuozengData; //将荧光数据按照反应孔位置存储
        QList<QList<QHash<QString, QString>>> deltaKuozengData; //将荧光数据按照反应孔位置存储

        for ( int reaction_number=0; reaction_number<niheyingGuangData[0].size(); reaction_number++)
        {
            QList<QHash<QString, QString>> cycles_temp;    //用来存储某一个孔位的多次循环信息
            QList<QHash<QString, QString>> cycles_temp2;    //用来存储某一个孔位的多次循环信息

            for ( int cycles_times=0; cycles_times<niheyingGuangData.size(); cycles_times++)
            {
                //第cycles_times循环reaction_number孔位的拟合荧光值
                cycles_temp.append(niheyingGuangData[cycles_times][reaction_number]);
                //第cycles_times循环reaction_number孔位的delta荧光值
                cycles_temp2.append(deltayingGuangData[cycles_times][reaction_number]);
            }
            //将这个孔位的多次循环信息存到kuozengData里面
            kuozengData.append(cycles_temp);
            deltaKuozengData.append(cycles_temp2);
        }

        int rows = len1+3; //定义行位置

        //        vector<QString>test_out = {"1","2","3","4"};

        for (int letter_number=0; letter_number<kuozengData.size(); letter_number++)
        {
            for(int target_number=1; target_number<=4; target_number++)
            {
                //判断靶基因中是否包含报告基因
                if(targetTable[QString::number(target_number)]=="")
                {
                    continue;
                }

                for (int cycles_number=0; cycles_number<kuozengData[0].size(); cycles_number++)
                {
                    curSheet->writeNumeric(rows,1,static_cast<double>(letter_number+1), numericFormat);
                    curSheet->writeString(rows,2,reactionPlace[letter_number]);
                    curSheet->writeNumeric(rows,3,static_cast<double>(cycles_number+1), numericFormat);
                    curSheet->writeString(rows,4,targetTable.value(QString::number(target_number)));
                    curSheet->writeNumeric(rows,5,QString::number((kuozengData[letter_number][cycles_number].value(QString::number(target_number))).toDouble(), 'f', 0).toInt(), numericFormat);
                    curSheet->writeNumeric(rows,6,QString::number((deltaKuozengData[letter_number][cycles_number].value(QString::number(target_number))).toDouble(), 'f', 0).toInt(), numericFormat);
                    QString target_name = targetTable.value(QString::number(target_number));
                    double dCt = (ctInfo[letter_number][Target_number.value(target_name)]).toDouble();
                    // 判断dct是否为nan：是，写入字符串形；不是，写入数字
                    qIsNaN(dCt) ? curSheet->writeString(rows,7, QString::number(dCt))
                                : curSheet->writeNumeric(rows,7,dCt, ctFormat);
                    //插入完一行数据，行数加1
                    rows++;
                }
            }
            // 休眠
            this->sleep(EXPORT_SLEEP_TIME);
        }
    }

    LOG << "扩增函数结束";

    //保存文件
    if (!xlsx.saveAs(filename))
    {
        return false;
    }
    return true;

}

//将qstring转wchar_t

const wchar_t *ExportFileService:: str2char(QString str)
{
    const wchar_t* wstr = reinterpret_cast<const wchar_t *>(str.utf16());
    return wstr;
}


//处理样本信息的样本孔
QList<QHash<QString,QString>> ExportFileService::disposeReactionWells(Sample sampleList[96],Target targetList[96][20])
{
    vector<QString> index = {"A","B","C","D","E","F","G","H"};
    QHash<QString,vector<QString>> sampleInfo;
    QList<QHash<QString,QString>> reactionInfo;

    //生成样本信息查询表
    int reactionNum=1;
    for (int i=0; i<8; i++)
    {
        int num = 1;
        for (int j=i; j<96; j+=8)
        {
            vector<QString> tmp;
            tmp.push_back(sampleList[j].name);
            tmp.push_back(sampleList[j].color_value);
            tmp.push_back(QString::number(reactionNum));

            sampleInfo.insert(index[i]+QString::number(num),tmp);
            reactionNum += 1;
            num += 1;
        }

    }


    //生成反应孔信息
    for (int i=0; i<8; i++)
    {
        int num = 1;
        for (int j=i; j<96; j+=8)
        {
            for(int k=0; k<4; k++)
            {
                //                if(targetList[j][k].name != "null")
                //                {
                QHash<QString,QString> tmp;

                tmp.insert("num",sampleInfo.value(index[i]+QString::number(num))[2]);
                tmp.insert("place",index[i]+QString::number(num));
                tmp.insert("sampleName",sampleInfo.value(index[i]+QString::number(num))[0]);
                tmp.insert("sampleColor",sampleInfo.value(index[i]+QString::number(num))[1]);
                tmp.insert("targetName",targetList[j][k].name);
                tmp.insert("targetColor",targetList[j][k].color);
                tmp.insert("task",targetList[j][k].type);
                tmp.insert("reporter",targetList[j][k].reporter);
                tmp.insert("quencher",targetList[j][k].quencher);
                tmp.insert("quantity",targetList[j][k].quantity);
                tmp.insert("explain",targetList[j][k].explain);

                reactionInfo.append(tmp);
                //                }

            }

            num += 1;

            // 休眠
            this->sleep(EXPORT_SLEEP_TIME);
        }

    }

    return reactionInfo;
}

/* 导出结束函数 */
bool ExportFileService::exportFinished(){
    //打开现存xlsx文件
    QXlsx::Document xlsx(filename);
    //选择样本设置表
    xlsx.selectSheet("样本设置");
    //保存文件
    if (!xlsx.saveAs(filename))
    {
        return false;
    }
    return true;
}

/* 休眠函数 */
void ExportFileService::sleep(int msec){
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime)
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
